package com.csw.android.ffmpegtest.ui.section1

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.Surface
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import com.csw.android.ffmpegtest.R
import com.csw.android.ffmpegtest.databinding.LayoutSection103Binding
import com.csw.android.ffmpegtest.ui.base.DataBindingFragment

/**
 *使用SurfaceView渲染一张图片
 */
class Section103 : DataBindingFragment<LayoutSection103Binding>() {

    override fun getContentViewID(): Int {
        return R.layout.layout_section_103
    }

    override fun initData() {
        super.initData()
        dataBinding?.content?.run {
            val pictureView = PictureView(context)
            addView(
                pictureView,
                ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
            )
            pictureView.setPictureId(R.drawable.benxi)
//            var times = 0
//            addLifecycleTask(Observable.interval(0, 16, TimeUnit.MILLISECONDS)
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe {
//                    times++
//                    pictureView.setPictureId(if (times % 2 == 0) R.drawable.benxi else R.mipmap.ic_launcher)
//                }
//            )
        }
    }

    class PictureView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : SurfaceView(context, attrs, defStyleAttr) {
        private var drawThread: DrawThread? = null
        private var windowBounds: Rect? = null
            set(value) {
                field = value
                drawThread?.refresh()
            }
        private var surface: Surface? = null
        private var picture: Drawable? = null
            set(value) {
                field = value
                drawThread?.refresh()
            }

        init {
            holder.addCallback(object : SurfaceHolder.Callback {
                override fun surfaceCreated(holder: SurfaceHolder) {
                    surface = holder.surface
                    drawThread = DrawThread(this@PictureView).apply { start() }
                }

                override fun surfaceChanged(
                    holder: SurfaceHolder,
                    format: Int,
                    width: Int,
                    height: Int
                ) {
                    windowBounds = Rect(0, 0, width, height)
                }

                override fun surfaceDestroyed(holder: SurfaceHolder) {
                    surface = null
                    drawThread?.release()
                    drawThread = null
                }
            })
        }

        fun setPictureId(pictureId: Int) {
            picture = ContextCompat.getDrawable(context, pictureId)?.apply {
                setBounds(0, 0, intrinsicWidth, intrinsicHeight)
            }
        }

        fun doDraw() {
            val drawBounds = windowBounds
            val s = surface
            val p = picture
            if (drawBounds != null && s != null) {
                var canvas: Canvas? = null
                try {
                    canvas = s.lockCanvas(drawBounds)
                    //刷新屏幕
                    canvas.drawColor(Color.WHITE)
                    //绘制图片
                    p?.run {
                        canvas.save()
                        canvas.translate(drawBounds.width() / 2f, drawBounds.height() / 2f)
                        canvas.translate(bounds.width() / -2f, bounds.height() / -2f)
                        draw(canvas)
                        canvas.restore()
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                } finally {
                    if (canvas != null) {
                        s.unlockCanvasAndPost(canvas)
                    }
                }
            }
        }
    }

    /**
     * SurfaceView优势在于子线程绘制和双缓冲画面，这里开启一个子线程用于绘制控制，
     * 一般来讲绘制有两种，一种是定时刷新，如动画，要达到最佳效果当然是根据屏幕刷新率来刷新，比如60fps，一般通
     * 过Thread.sleep()来控制刷帧间隔。
     * 另一种是有画面内容有更新时刷新，一般通过对象锁来实现，无更新时通过Object.wait()进入休眠，内容更新后通过
     * Object.notify()唤醒线程刷新。
     * 两者各有优势，根据情况使用，这里明显图片资源改变才会需要刷新，所以实现的是第二种
     *
     * emmm，用线程有个比较大的缺点
     */
    private class DrawThread(val pictureView: PictureView) : Thread() {
        private val lock = Object()
        private var running: Boolean = false

        fun refresh() {
            synchronized(lock) {
                lock.notifyAll()
            }
        }

        fun release() {
            running = false
            refresh()
        }

        override fun start() {
            super.start()
            running = true
        }

        override fun run() {
            super.run()
            while (running) {
                pictureView.doDraw()
                synchronized(lock) {
                    lock.wait()
                }
            }
        }
    }
}